using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Odbc;
using Entity;
using BussisnesException;
using System.Data.OleDb;

namespace DAO
{
	/// <summary>
	/// Clase de acceso a los datos del user.
	/// </summary>
	public class UserDAO : AbstractDAO<User>{
		
		private const string FIELD_NAME="USER_NAME";
		private const string FIELD_PASS="PASS";
		private const string FIELD_EMAIL="MAIL";
		private const string FIELD_IMG="IMAGE_PATH";
        private const string FOLLOWS_USER = "USER";
        private const string FOLLOWS_FOLLOWER = "FOLLOWER";
        private const string TABLE_USERS_FOLLOWS = "FOLLOWS";
		private const string TABLE_NAME="USERS";
	
		private const string FIND_BY_START_NICK="SELECT * FROM "+TABLE_NAME+" WHERE " + FIELD_NAME + "like ?";
        private const string FIND_FOLLOWERS_BY_NICK = "SELECT * FROM " + TABLE_NAME + "," + TABLE_USERS_FOLLOWS + " WHERE " + FIELD_NAME + "=" + FOLLOWS_FOLLOWER + " AND " + FOLLOWS_USER + " =@" + FIELD_NAME;
        private const string FIND_FOLLOWS_BY_NICK = "SELECT * FROM " + TABLE_NAME + "," + TABLE_USERS_FOLLOWS + " WHERE " + FIELD_NAME + "=" + FOLLOWS_USER + " AND " + FOLLOWS_FOLLOWER + " =@" + FIELD_NAME;
        private const string INSERT_FOLLOW = "INSERT INTO " + TABLE_USERS_FOLLOWS +" values (@"+FOLLOWS_USER+","+"@"+FOLLOWS_FOLLOWER+")";
        private const string DELETE_FOLLOW = "DELETE FROM " + TABLE_USERS_FOLLOWS + " WHERE " + FOLLOWS_USER + "=@" + FOLLOWS_USER + " AND " + FOLLOWS_FOLLOWER + "=" + "@" + FOLLOWS_FOLLOWER + ")";
		public UserDAO(){}

		protected override OleDbCommand createOperationCommand(OperationType operation, User entidad){
			String sql = getSql(operation);
            Dictionary<String, Object> parameters = new Dictionary<String, Object> { 
            { "@"+FIELD_NAME, entidad.Username } ,
            { "@"+FIELD_EMAIL, entidad.Email } ,
            { "@"+FIELD_IMG, entidad.ImagePath } ,
            { "@"+FIELD_PASS, entidad.Password } 
            };
            return createCommand(sql, parameters);
        }
		
		private string getSql(OperationType type){
			string sql ="";
			if(OperationType.INSERT.Equals(type)){
                sql = "INSERT INTO " + getTableName() + " (" + FIELD_NAME + "," + FIELD_EMAIL + "," + FIELD_IMG + "," + FIELD_PASS + ")" +
                "values(@" + FIELD_NAME +", @" + FIELD_EMAIL +", @"+FIELD_IMG +", @"+FIELD_PASS + ")";
			}else{
                sql = "UPDATE " + getTableName() + 
                    " set(" + FIELD_PASS  + "=@" + FIELD_PASS + "," + 
                              FIELD_EMAIL + "=@" + FIELD_EMAIL+"," + 
                              FIELD_IMG   + "=@" + FIELD_IMG  + ") where " + 
                              FIELD_NAME  + "=@" + FIELD_NAME;
			}
			return sql;
		}

        public void inserFollow(String user, String follower) {
            OleDbCommand cmd = null;
            try
            {
                Dictionary<String, Object> parameters = new Dictionary<String, Object> { 
                { "@"+FOLLOWS_USER, user } ,
                { "@"+FOLLOWS_FOLLOWER, follower} 
                };
                cmd = createCommand(INSERT_FOLLOW, parameters);
                cmd.ExecuteNonQuery();
            }
            finally 
            {
                closeConnection(null, cmd);
            }
        }
        public void deleteFollow(String user, String follower)
        {
            OleDbCommand cmd = null;
            try
            {
                Dictionary<String, Object> parameters = new Dictionary<String, Object> { 
                { "@"+FOLLOWS_USER, user } ,
                { "@"+FOLLOWS_FOLLOWER, follower} 
                };
                cmd = createCommand(INSERT_FOLLOW, parameters);
                cmd.ExecuteNonQuery();
            }
            finally
            {
                closeConnection(null, cmd);
            }
        }
		/// <summary>
		/// Crea una instancia de la clase User y la carga con 
		/// los datos contenidos en el objeto DataReader.
		/// </summary>
		/// <param name="dr">Objeto DataReader con los datos del User.</param>
		/// <returns>Objeto User con los datos cargados.</returns>
		protected override User toEntity(OleDbDataReader dr){
			User entidad = new User();
			entidad.Username = dr[FIELD_NAME].ToString();
			entidad.Password = dr[FIELD_PASS].ToString();
			entidad.Email = dr[FIELD_EMAIL].ToString();
            entidad.ImagePath = dr[FIELD_IMG].ToString();
			return entidad;
		}
        protected override void completeEntity(OleDbDataReader dr, User entidad)
        {
            //TODO: -VEr esto
        }
		/// <summary>
		/// Se buscan Users por distintos criterios.
		/// </summary>
		/// <returns>Lista de objetos con datos de los Users encontrados.</returns>*/
		public List<User> findByLikeNick(string nick){
            // Objeto con datos del User.
            List<User> users = new List<User>();
            try{
                OleDbCommand command = createCommand(FIND_BY_START_NICK, createUserParameter("%" + nick + "%"));
               users = find(command);
            }catch (Exception ex){
            	// En caso de que se produzca un error, se lo lanza hacia la
                // capa superior.
               throw new ObjectNotFoundException(ex,"El usuario: "+ nick + " no existe");
               
            }
            return users;
		}
		
			/// <summary>
		/// Se buscan Users por distintos criterios.
		/// </summary>
		/// <returns>Lista de objetos con datos de los Users encontrados.</returns>*/
		public List<User> findFollowers(string nick){
            // Objeto con datos del User.
            List<User> users = new List<User>();
            try{
                OleDbCommand command = createCommand(FIND_FOLLOWERS_BY_NICK, createUserParameter(nick));
               users = find(command);
            }catch (Exception ex){
            	// En caso de que se produzca un error, se lo lanza hacia la
                // capa superior.
               throw new ObjectNotFoundException(ex,"El usuario: "+ nick + " no existe");
               
            }
            return users;
		}
		/// Se buscan Users por distintos criterios.
		/// </summary>
		/// <returns>Lista de objetos con datos de los Users encontrados.</returns>*/
		public List<User> findFollows(string nick){
            // Objeto con datos del User.
            List<User> users = new List<User>();
            try{
                OleDbCommand command = createCommand(FIND_FOLLOWS_BY_NICK, createUserParameter(nick));
               users = find(command);
            }catch (Exception ex){
            	// En caso de que se produzca un error, se lo lanza hacia la
                // capa superior.
               throw new ObjectNotFoundException(ex,"El usuario: "+ nick + " no existe");
               
            }
            return users;
		}
		
		protected override string getTableName(){
			return TABLE_NAME;
		}
		
		protected override string getIdColumn(){
            return FIELD_NAME;
		}
        
        private Dictionary<String,Object> createUserParameter(String user){
            return new Dictionary<string, object> { {"@"+FIELD_NAME, user}};
        }
	}
    
}
